#include "communication.h"
#include "tcp/tcp.h"
#include "tls_tcp/tls_tcp.h"
#include <sys/time.h>
#include <utils/logger.h>
namespace communication {

    const int32_t COMMUNICATION_MAX_BUF_SIZE = 256;
    const int32_t COMMUNICATION_WAIT_MSECS = 500;
    Communication::Communication() {}

    std::shared_ptr<Communication> Communication::GetCommunicationInstance(int protoId, bool isTls)
    {
        switch (protoId) {
            case Communication::CT_TCP:
                if (!isTls) {
                    return std::make_shared<communication::Tcp>();
                } else {
                    return std::make_shared<communication::TlsTcp>();
                }
                break;
            case Communication::CT_UDP:
            case Communication::CT_HTTP:
            default:
                break;
        }
    return nullptr;
    }

bool Communication::IsRun() const {
    return bRun_;
}

void Communication::Start(const std::string &host, int port, int32_t timeout)
{
    if (bRun_) {
        HTELINK_LOG_WARN("%s://%s:%d has been running", name().c_str(), host_.c_str(), port_);
        return;
    }
    host_ = host;
    port_ = port;
    timeout_ = timeout;
    HTELINK_LOG_INFO("%s://%s:%d start to running", name().c_str(), host_.c_str(), port_);
    threadTask_ = std::thread([this]() {
        bRun_ = true;
        Run();
    });
}
void Communication::Stop()
{
    HTELINK_LOG_INFO("%s://%s:%d stop", name().c_str(), host_.c_str(), port_);
    bRun_ = false;
    if (threadTask_.joinable()) {
        threadTask_.join();
    }
}
void Communication::Run()
{
	while (bRun_) {
		std::this_thread::sleep_for(std::chrono::milliseconds(COMMUNICATION_WAIT_MSECS));
        if (!IsConnected()) {
            Connect(host_, port_);
            if (onStatus_ && IsConnected()) {
                onStatus_(true);
            }
            continue;
        }
        WaitForRecv();

        if (onStatus_ && !IsConnected()) {
            onStatus_(false);
        }
	}
	DisConnect();
}
bool Communication::Send(const char *buf, int32_t len) {
    if (!IsConnected()) {
        return false;
	}
	int32_t sendLen = SendData(buf, len);
    return sendLen == len;
}
void Communication::OnStatus(const std::function<void(bool)> &onStatus) {
    onStatus_ = onStatus;
}
void Communication::OnReceive(
    const std::function<void(char *buf, int32_t len)> &onReceive) {
    onReceive_ = onReceive;
}
void Communication::WaitForRecv()
{
    char buf[COMMUNICATION_MAX_BUF_SIZE];
    int32_t len = RecvData(buf, COMMUNICATION_MAX_BUF_SIZE, timeout_);
    if (len > 0) {
		if (onReceive_) {
			onReceive_(buf, len);
		}
	}
    if (len < 0) {
        DisConnect();
    }
}
} // namespace communication